Skip to content

audit H2/M1/M11: say what cannot be done, say what is checked, stop keeping two copies - #13

Merged
ojassug merged 1 commit into
mainfrom
audit-decisions
Aug 11, 2026
Merged

audit H2/M1/M11: say what cannot be done, say what is checked, stop keeping two copies#13
ojassug merged 1 commit into
mainfrom
audit-decisions

Conversation

@ojassug

@ojassug ojassug commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Closes the last three audit items — H2, M1 and M11. The audit filed these as decisions
rather than tasks
, because each had a legitimate "narrow the product" answer and a legitimate
"build more" one. Reasoning, including the options refused, in DECISIONS §46.

Every audit item is now closed. What remains is the architectural work in the status doc's §5,
chiefly Phase 1c.


H2 — decided: report why, don't narrow the accepted set

Twelve of nineteen recognised extensions can't produce a non-zero reduction under any flag
combination, and that was indistinguishable from a file with nothing worth compressing.

Refused: rejecting --language go. Stronger honesty signal, but it deletes a working
behaviour — pass-through is byte-identical and harmless.

Taken: trace.languageSupport carries supported / unsupported / unsupportedLanguages /
noneSupported / reason, and validate() raises an info issue (LANGUAGE_NOT_ELIDIBLE)
that doesn't vote on the verdict. Same correction M5a made for budgets, one layer down.

Three things worth flagging for review:

  • The predicate had to come from the gate, not from intuition. A first version asked "does
    the item yield symbols or markers?"
    and called Go supported — a trivial Go file yields
    exactly one symbol, import:fmt, an incidental match by the TypeScript import regex. The
    answer is exactly supportsRegionElision. Measured: 3 of 17 probed languages, which is the
    audit headline and the corpus agreeing independently.
  • The field crosses four whitelists that each enumerate their keys — validate()'s return,
    createValidationReport, buildTrace, createOptimizationTrace. Three dropped it silently.
    The test asserts on the trace, not on validate(), for that reason.
  • A friendly CLI notice was written and then removed. stderr is a JSON trace document and
    consumers parse the whole stream — four of this repo's own tests do. Prepending prose broke
    them. The explanation now lives inside the report as reason.

M1 — decided: correct the docs, don't wire the compiler API

The TypeScript "AST-lite validator" builds no AST. Probed against the shipped code rather than
copied from the audit (three audit claims here have failed that test — §40, §42, §45), all of it
reproduced:

Input Verdict
const x = ; · import from "x"; · let 123abc = 5; · const a = 1 +++++ 2; · English prose PASS
super(; } FAIL

Refused: ts.createSourceFile. On cost, not principle — typescript is a dev dependency
today; promoting it to runtime costs install size and parse latency against a lexer that runs in
single-digit milliseconds.

Taken: README and CLAUDE.md now say bracket/quote integrity, with a per-language table of
what each validator does and does not catch. test/unit/validator-guarantee.test.ts pins every
row — strengthen a validator and it fails on purpose, and the table has to move with it.

M11 — decided: retire the narratives and root planning artifacts

Twelve files, 226 KB. Markdown 31 files → 19; markdown:src 1.40:1 → 0.95:1.
docs/retired-documents.md maps each file to where its conclusion lives and gives the git show
command to read the original.

The premise was stale, and measuring first changed what the decision was about. M11 was filed
as 4.1:1; measured before acting it was already 1.40:1 — and not because the docs had
shrunk (they'd grown to 726 KB) but because src/ grew faster. Since 32.8% of src/ is comment
prose
, prose:code actually ran ~2.6:1. So the finding isn't about bytes, it's about two copies
of an argument kept in sync by hand
. In-source commentary isn't that, and none of it was touched.

Twenty-five source and test comments cite a retired document — the check this option called
for, and the thing that nearly made it a bad change. They're marked [retired] rather than
re-pointed: the citation names something git still holds, whereas re-pointing 25 citations at
DECISIONS sections by hand risks mapping some to the wrong place — trading a volume problem for a
correctness one. CHANGELOG.md and DECISIONS.md keep their older citations untouched, each with
a note saying why: they record what was true when written.


Verification

  • 599 tests passing (was 566), typecheck and lint clean.
  • 574 of 574 corpus rows identical to the pre-change engine across 17 fields, same frozen
    corpus, varying only dist/. H2 refactored selectElisionRegions to derive its gate from a
    shared predicate, so this was a real risk rather than a formality.
  • Verified end-to-end on the built CLI: a Go file reports noneSupported with its reason, a
    TypeScript file doesn't, and stderr still parses as JSON.

The corpus recipe moves again, both changes mine: typescript 60 → 61
(src/core/validation/language-support.ts) and prose 29 → 18 (twelve retired, one added).
collect.js refused on both before measuring anything.

Left undone, deliberately

cli/bench-table-renderer.ts:97 still prints a risk column sourced from riskTolerance, which
H4 established no stage reads. It's now the only reader of that field, and a benchmark column
implies the row's numbers depend on it. Small and real — left out because changing what a
benchmark reports is a measurement change, not a documentation one.

🤖 Generated with Claude Code

…keeping two copies

Closes the last three audit items — H2, M1 and M11 — which the audit filed as
decisions rather than tasks because each had a legitimate "narrow the product"
answer and a legitimate "build more" one. Reasoning, including the options
refused, in DECISIONS §46.

H2 — decided: report why, do not narrow the accepted set.

Twelve of nineteen recognised extensions cannot produce a non-zero reduction
under any flag combination, and that was indistinguishable from a file with
nothing worth compressing. Rejecting `--language go` would be the stronger
honesty signal and would also delete a working behaviour — pass-through is
byte-identical and harmless. So every language is still accepted, and the run now
says when elision cannot reduce it: `trace.languageSupport` carries `supported`,
`unsupported`, `unsupportedLanguages`, `noneSupported` and a `reason`, and
`validate()` raises an info issue, `LANGUAGE_NOT_ELIDIBLE`, that does not vote on
the verdict. Same correction M5a made for budgets, one layer down.

Three things this cost, all worth knowing. The predicate had to be derived from
the gate rather than guessed: a first version asked "does the item yield symbols
or markers?" and called Go supported, because a trivial Go file yields exactly one
— `import:fmt`, an incidental match by the TypeScript import regex. The answer is
exactly `supportsRegionElision`, since a symbol-bearing item cannot be elided
whole (§43) and a symbol-free item's whole-item elision destroys every content
marker and fails the same gate a step later. Measured, that predicts 3 of 17
probed languages — TypeScript, JavaScript, Python — which is the audit headline
and the corpus agreeing independently.

The field also had to be threaded through four separate whitelists that each
enumerate their keys: `validate()`'s return, `createValidationReport`,
`buildTrace` and `createOptimizationTrace`. Three dropped it silently, every time
presenting as `trace.languageSupport: undefined` with everything else correct;
the test asserts on the trace rather than on `validate()` for that reason.

And a friendly CLI notice was written, then removed. The CLI prints the trace to
stderr as a JSON document and consumers parse the whole stream — four of this
repo's own tests among them. Prepending prose broke them. The explanation now
lives inside the report as a `reason` field, so it is both machine-readable and
readable and stderr stays parseable.

M1 — decided: correct the documentation, do not wire the compiler API.

The TypeScript "AST-lite validator" builds no AST; it is a lexer detecting
unbalanced brackets and unterminated strings. Probed against the shipped code
rather than taken from the audit — three audit claims in this project have failed
that test (§40, §42, §45) — all of it reproduced: `const x = ;`,
`import from "x";`, `let 123abc = 5;`, `const a = 1 +++++ 2;` and plain English
prose all pass; only `super(; }` fails. Python is stronger and still passes prose;
JSON is a real parser.

`ts.createSourceFile` was refused on cost, not principle: `typescript` is a dev
dependency today and promoting it to runtime costs install size and parse latency
against a lexer running in single-digit milliseconds. Instead README and CLAUDE.md
now say "bracket/quote integrity" and carry a per-language table of what each
validator does and does not catch, and
`test/unit/validator-guarantee.test.ts` pins every row as a characterization test
— strengthen a validator and it fails on purpose, and the table moves with it.

M11 — decided: retire the narratives and the root planning artifacts.

Twelve files, 226 KB; markdown 31 files -> 19, markdown:src 1.40:1 -> 0.95:1.
`docs/retired-documents.md` maps each file to where its conclusion lives and gives
the `git show` command to read the original.

The premise was stale and measuring it first changed what the decision was about.
M11 was filed as 4.1:1; measured before acting it was already 1.40:1 — and not
because the docs had shrunk (they had grown to 726 KB) but because src/ grew
faster. Since 32.8% of src/ is comment prose, prose:code actually ran ~2.6:1. That
reframes the finding: the problem is not bytes, it is two copies of an argument
kept in sync by hand. In-source commentary is not that, and none of it was
touched.

Twenty-five source and test comments cite a retired document — the check the
option called for, and the thing that nearly made this a bad change. They are
marked `[retired]` rather than re-pointed: the citation names something git still
holds, whereas re-pointing 25 citations at DECISIONS sections by hand would risk
mapping some of them to the wrong place, trading a volume problem for a
correctness one. CHANGELOG.md and DECISIONS.md keep their older citations
untouched, each with a note saying why — they record what was true when written.

Measurement: 574 of 574 corpus rows identical to the pre-change engine across 17
fields, same frozen corpus, varying only dist/. H2 refactored
`selectElisionRegions` to derive its gate from a shared predicate, so this was a
real risk rather than a formality.

The corpus recipe moves again and both changes are mine: typescript 60 -> 61
(src/core/validation/language-support.ts) and prose 29 -> 18 (twelve documents
retired, one added). `collect.js` refused on both before measuring anything.

Suite: 599 passing (was 566), typecheck and lint clean.

Every audit item is now closed. What remains is the architectural work in the
status doc's §5, chiefly Phase 1c.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ojassug
ojassug merged commit 4a5026d into main Aug 11, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant